#include <pthread.h>
#include <dlfcn.h>
#include <unistd.h>
#include  <fcntl.h>
#include  <stdlib.h>
#include  <dirent.h>
#include <string.h>
#include <errno.h>

#include "module_interface.h"

#include "cmd_core.h"
#include "comm.h"
#include "comm_pipe_factory.h"

#define BUF_SIZE 960*2*2

#define FIFO_PATH "./comm_pipe"

int get_current_exe_path(char *processdir, int len)
{
        char* path_end;  

        if(readlink("/proc/self/exe", processdir,len) <=0) {
                return -1;  
	}

        path_end = strrchr(processdir,  '/');  
        if(path_end == NULL) {
                return -1;  
	}
        ++path_end;  
        *path_end = '\0';  
        return (int)(path_end - processdir); 
}

int load_cmdexe_module(const char *path)
{
	int ret = 0;
	void *handle;
	cmdexe_module_t *hmi;
	const char *sym = "CUR_MODULE";

	handle = dlopen(path, RTLD_NOW);
	if (handle == NULL) {
		char const *err_str = dlerror();
		perror(err_str);
		ret = -EINVAL;
		goto done;
	}
	/* Get the address of the struct hal_module_info. */
	hmi = (cmdexe_module_t *)dlsym(handle, sym);
	if (hmi == NULL) {
		printf("load: couldn't find symbol %s", sym);
		ret = -EINVAL;
		goto done;
	}

	if(register_module_byname(hmi->name)){
		printf("register module %s fail\n", hmi->name);
		return -1;
	}
	printf("register module %s OK\n", hmi->name);

	if((ret = register_cmds_auto_end(hmi->name, hmi->pcmds)) < 0){
		perror("Register cmds error\n");
		return -1;
	}

	hmi->init_module();
done:
	return ret;
}

int search_cmd_module_in_dir(const char *path)
{
	int ret = 0;
	char *full_path;
	DIR *pdir;
	struct dirent *pdirent;

	pdir = opendir(path);
	if (!pdir) {
		perror("Unable to open dir:");
		perror(path);
		return -1;
	}

	while(( pdirent = readdir( pdir )) != NULL) {
		if (!strstr(pdirent->d_name, "cmdexe")) {
			continue;
		}

		printf("Found module: %s\n", pdirent->d_name);
		ret++;

		full_path = (char *)malloc(strlen(path) + 
					strlen(pdirent->d_name) + 1);
		strncpy(full_path, path, strlen(path) + 1);
		strncat(full_path, pdirent->d_name, strlen(pdirent->d_name));
		load_cmdexe_module(full_path);
	}
	return ret;
}

int search_load_cmd_modules()
{
	char path[64];
	int flag = 0;
	char *pchar;
	
	if(!getcwd(path, sizeof(path))) {
		perror("get current directory\n");
		flag = -1;
	}

	if(flag >= 0) {
		pchar = path + strlen(path) - 1;
		if (*pchar != '/') {
			pchar++;
			*pchar++ = '/';
			*pchar = '\0';
		}
		search_cmd_module_in_dir(path);	
	}

	flag = 0;
	if(get_current_exe_path(path, sizeof(path)) < 0){
		perror("get execute file path fail, pass this path\n");
		flag = -1;
	}

	if(flag >= 0) {
		search_cmd_module_in_dir(path);	
	}

	return 0;
}

int main(int argc, char** argv)
{
	const int buf_len = 256;
	const int ret_buf_len = 256;
	char buf[buf_len];
	char ret_buf[ret_buf_len];
	int len;
	int ret;
	sem_t *sem_read;
	comm_factory *cur_factory; 
	comm *cur_comm;

	if(init_module_core()){
		perror("Init module core system error\n");
		exit(-1);
	}
	printf("Init module core system OK\n");

	search_load_cmd_modules();
	
#if 0
	if(init_sensor_hal_test()){
		perror("Register sensor HAL test error\n");
	}
	printf("Register sensor HAL test OK\n");
#endif

	cur_factory = new comm_pipe_factory();
	cur_comm = cur_factory->create_comm();
	cur_comm->open((void *)FIFO_PATH);
	sem_read = cur_comm->get_semaphore();

	while(1){
		sem_wait(sem_read);
		len = cur_comm->read_a_line(buf,buf_len);
		buf[len] = '\0';
		printf("Command:%s\n",buf);
		if(execute(buf, ret_buf, ret_buf_len)){
			printf("execute FAIL!\n");
		}else{
			printf("execute OK!\n");
		}
		cur_comm->write(ret_buf, strlen(ret_buf));
	}
	return ret;
}
